home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
PROGRAMM
/
CC_C
/
0151.ZIP
/
BUGGER.ASM
< prev
next >
Wrap
Assembly Source File
|
1985-09-28
|
41KB
|
2,022 lines
title Fido's Bugger
name bugger
;
;****************************************
;* *
;* Bugger *
;* *
;* For: Fido *
;* *
;* T. Jennings 20 Oct 83 *
;* created 29 April 81 *
;* *
;****************************************
;
cgroup group code
dgroup group data
;
; This debugger and boot rom supports the
;following hardware:
;
;Intel SBC 86/12:
; Console on the serial port,
; 9600 baud, no parity, 8 bits
;Memory:
; 64K minimum; buggers stack and
; work space is at 0f80:0000.
; Disk boot sector loaded at 10:0
;Diskettes:
; A Comark MF-85 WD1793 controller,
; 8" and 5" diskettes.
;Hard Disk:
; A Xebec Controller on a DTC Host
; Interface, supporting a typical
; 10 meg wini, drive type = 4.
;Other: A loudspeaker tied to bit 0 of
; the 8255 Port C.
;
; Bugger inits the hardware needed to boot,
;some interrupt vectors, then autoboots the
;hard disk (A:). It makes funny noises while
;booting.
;
; If Control-C is hit, bugger jumps into
;command mode; see BUGGER.DOC for details.
;
;
;The power on jump at FFFF:0000 must be
;patched into the ROMs after burning this
;code:
;
;2716's (2K)
;
;EVEN PROM: 07f8: ea 00 fe
;ODD PROM: 07f8: 00 00
;
;2732's (4K)
;
;EVEN PROM: 0ff8: ea 00 ff
;ODD PROM: 0ff8: 00 00
;
;What is being patched in is:
;
; jmp far 0fe00:0000 ;(2716)
; jmp far 0ff00:0000 ;(2732)
;
;Baud rate for the serial port
;
baud_rate equ 9600
baud equ 768 / (baud_rate / 100)
;
;Where our data segment is:
;
dataseg equ 0f80h
page
;
;Interrupts used:
;
;
;Floppy disk read interrupt: A standard Fido
;disk BIOS table at DS:BX. Status in AL; carry
;if error. These vectors must be below 00100h,
;or 0010:0000, since thats where the boot is
;loaded, and the 1K boot sector wipes out the
;interrupt vectors.
;
FLP_INT equ 32 ;floppy access
RMS_INT equ 33 ;hard disk access
TRC_INT equ 1 ;single step
BRK_INT equ 3 ;break point
BRK_INST equ 0cch ;INT 3
CR equ 0dh ;carriage return
LF equ 0ah ;line feed
include iodef.ash
include disk.ash
include disk2.ash
page
;
;Where we load the boot sector. This is
;in the middle of the interrupt vectors,
;and it assumes the boot sector isnt big
;enough to trash our vectors.
;
bootseg segment at 10h
org 0
boot label far
bootseg ends
;
;Start of ROM code. cgroup must be
;first so the linker will put things in
;the right order.
;
code segment byte public 'code'
assume cs:cgroup
bugger: jmp start
;
;Old interface. Do not use it.
;
interface proc far
call ina
ret
call outa
ret
call foo ;deleted call,
ret ;dummy out.
call execute
ret
call dtc
ret
;
;New interface, accessed by the software
;interrupts. Call the ROM code,
;return, trashing the flags.
;
hboot: call dtc
ret 2
fboot: call execute
ret 2
interface endp
foo: ret
code ends
data segment byte public 'data'
stack dw (?)
;
;Work space for the DTC/Xebec controller
;drivers and initialization.
;
cmdtbl db 9 dup (?)
dattbl db 8 dup (?)
;
;DTC/Xebec command string.
;
xcomand db (?) ;command,
lun db (?) ;unit, top sector,
hiaddr db (?) ;high sec byte,
lowaddr db (?) ;low sec byte,
scount db (?) ;sector count,
control db (?)
db 8 dup (?)
;
;breakpoint and go register save/display area
;these register save locations must be kept in
;this order.
;
dmp_ptr label word
brkfl dw (?) ;saved flags
brkax dw (?) ;saved ax
brkbx dw (?) ;saved bx
brkcx dw (?) ;saved cx
brkdx dw (?) ;saved dx
brksi dw (?) ;saved si
brkdi dw (?) ;saved di
brksp dw (?) ;saved sp
brkip dw (?) ;saved ip
ip_base dw (?) ;reloc reg
brkcs dw (?)
brkds dw (?)
brkes dw (?)
brkss dw (?)
brkbp dw (?) ;base pointer
;
;More data area. These don't have to be in
;any specific order.
;
noreloc db (?) ;no relocation
dmpoff dw (?) ;display addr
dmpseg dw (?) ;local ES
scratch db (?) ;scratch word,
bootnum dw (?) ;default drive,
;
;Breakpoint data.
;
brkflg db (?) ;true if break
brkadr dw (?) ;brk pnt addr
brkseg dw (?) ;brk pnt seg
brkinst db (?) ;saved inst
data ends
page
code segment byte public 'code'
assume cs:cgroup,ds:dgroup
;
;Data word to set DS.
;
dataloc dw dataseg
;
;Data tables here, to avoid MASM bugs.
;
ctable db 'g'
dw offset go
db 'x'
dw offset registers;dump regs
db 'r'
dw offset registers
db 's'
dw offset memchg ;change memory
db 'e'
dw offset memchg ;ditto
db 'd'
dw offset dump ;dump memory
db 'f'
dw offset fill ;fill memory,
db 'm'
dw offset blkmov ;move memory.
db 'i'
dw offset input ;port input
db 'o'
dw offset output ;port output.
db 't'
dw offset trace ;trace command,
db 'h'
dw offset arith ;do arithmetic
db 'l'
dw offset intel ;load hex,
db 'v'
dw offset intvec ;fiddle int vec
db 'b'
dw offset dboot ;disk boot
tlen equ ($ - ctable) / 3
page
eh db ' eh?',0
id1str db CR,"Fido, 1 December 84"
id2str db CR,"Booting from drive A:, "
db " Control-C to abort: ",0
dskstr db CR,"Disk read error",0
butstr db CR,"Bad boot sector",0
prompt db CR,'Ok.',0
regstr1 db CR,'ax bx cx dx si di '
db 'sp ip + rr ',CR,0
regstr2 db CR,'cs ds es ss bp TOS '
db 'NOS ....oditsz.a.p.c',CR,0
regtbl dw 'fl','ax','bx','cx','dx','si'
dw 'di','sp','ip','rr','cs'
dw 'ds','es','ss','bp'
rtblen equ ($ - regtbl) / 2
page
;
;Disk boot read tables. These are the
;standard Fido MSDOS BIOS disk tables. All
;boot sectors are track 0 sector 1. (First
;sector, damn IBM)
;
;Shugart 850, drive 0, DD1024 single sided,
;double density, eight 1024 byte sectors,
;77 tracks.
;
dd1024 db fread ;read command,
db 0 ;drive 0,
dw 0 ;track 0,
dw 1 ;sector 1,
dw 1 ;1 sector,
dw -1 ;current track unknown
db 1 ;double density,
db 15 ;gap length,
db 3 ;sec size,
db 255 ;data len,
dw 1024 ;sector size,
dw 0 ;DMA offset,
dw 10h ;DMA segment,
dw 8 ;sectors/track
dw 0 ;head 0,
dblen equ $ - dd1024
;
;Shugart 850, SD128 single sided single
;density 26 128 byte sectors per track.
;
sd128 db fread ;read command,
db 0 ;drive 0,
dw 0 ;track 0,
dw 1 ;sector 1,
dw 1 ;1 sector,
dw -1 ;current track unknown
db 0 ;single density,
db 0 ;gap length,
db 0 ;sec size,
db 0 ;data len,
dw 128 ;sector size,
dw 0 ;DMA offset,
dw 10h ;DMA segment,
dw 26
dw 0
;
;Tandon DMIBM8-1 single sided double density
;eight 512 byte sectors per track, 40 tracks.
;
ibm db fread ;read command,
db 2 ;drive 2,
dw 0 ;track 0,
dw 1 ;sector 1,
dw 1 ;1 sector,
dw -1 ;current track unknown
db 3 ;double density mini
db 0 ;gap length,
db 0 ;sec size,
db 0 ;data len,
dw 512 ;sector size,
dw 0 ;DMA offset,
dw 10h ;DMA segment,
dw 8 ;spt
dw 0 ;head
page
;RMS, HD256 8 heads 32 256 byte sectors/track,
;logically arranged as 192 spt.
;
rms db fread ;read command,
db 0 ;drive 0,
dw 0 ;track 0,
dw 1 ;sector 1,
dw 1 ;1 sector,
dw -1 ;current track unknown
db 0
db 0 ;gap length,
db 0 ;sec size,
db 0 ;data len,
dw 256 ;sector size,
dw 0 ;DMA offset,
dw 10h ;DMA segment,
dw 192 ;spt
dw 0
;
;Same as above, table for interrogating
;drive ready only.
;
rmsc db fcheck ;read command,
db 0 ;drive 0,
dw 0 ;track 0,
dw 1 ;sector 1,
dw 1 ;1 sector,
dw -1 ;current track unknown
db 0
db 0 ;gap length,
db 0 ;sec size,
db 0 ;data len,
dw 256 ;sector size,
dw 0 ;DMA offset,
dw 10h ;DMA segment,
dw 192 ;spt
dw 0 ;head
page
;
;Sound tables, for a 8253 clock rate
;of 1.23 MHz.
;
OCTAVE equ 2
CNOTE equ 9609 ;C
CSNOTE equ 9044 ;C#
DNOTE equ 8541 ;D
DSNOTE equ 8092 ;D#
ENOTE equ 7687 ;E
FNOTE equ 6988 ;F
FSNOTE equ 6684 ;F#
GNOTE equ 6406 ;G
GSNOTE equ 5913 ;G#
ANOTE equ 5694 ;A
ASNOTE equ 5301 ;A#
BNOTE equ 4959 ;B
NONOTE equ 0 ;no tone
ENDNOTE equ -1 ;end of list
EIGHTH equ 20
QUARTER equ 2 * EIGHTH
HALF equ 2 * QUARTER
FULL equ 2 * HALF
;
;Something wrong
;
fault label word
dw NONOTE,QUARTER
dw DNOTE,QUARTER
dw DSNOTE,HALF
dw CNOTE,QUARTER
dw CSNOTE,HALF
dw DNOTE,QUARTER
dw DSNOTE,HALF
dw CNOTE,QUARTER
dw CSNOTE,HALF
dw ENDNOTE
;
;Power up, alive.
;
alive label word
dw CNOTE,QUARTER
dw ANOTE,QUARTER
dw GNOTE,QUARTER
dw ENOTE,QUARTER
dw NONOTE,QUARTER
dw CNOTE,QUARTER
dw ANOTE,QUARTER
dw GNOTE,QUARTER
dw ENOTE,QUARTER
dw NONOTE,QUARTER
dw ENDNOTE
;
;While trying to boot
;
bootsong label word
dw ANOTE,HALF
dw FSNOTE,HALF
dw ENOTE,HALF
dw DNOTE,HALF
dw NONOTE,HALF
dw ENDNOTE
;
;Boot loaded, running DOS
;
dostune label word
dw CNOTE,QUARTER
dw DNOTE,QUARTER
dw ENOTE,QUARTER
dw FNOTE,QUARTER
dw GNOTE,QUARTER
dw BNOTE,QUARTER
dw ENDNOTE
;
;Bugger command error
;
blatz label word
dw DNOTE,EIGHTH
dw DSNOTE,EIGHTH
dw CNOTE,EIGHTH
dw CSNOTE,EIGHTH
dw ENDNOTE
page
;
;Set things up, init the hardware, try
;to boot.
;
start: mov ss,cs:dataloc
mov sp,offset stack
mov ds,cs:dataloc
call IOINIT ;clear hardware
mov bx,offset alive
call play ;make noise
mov ax,0
mov ds,ax ;install int
mov bx,BRK_INT * 4
mov word ptr [bx],offset brkntr
mov bx,BRK_INT * 4 + 2
mov word ptr [bx],cs
mov bx,TRC_INT * 4
mov word ptr [bx],offset brkntr
mov bx,TRC_INT * 4 + 2
mov word ptr [bx],cs
mov bx,FLP_INT * 4
mov word ptr [bx],offset fboot
mov bx,FLP_INT * 4 + 2
mov word ptr [bx],cs
mov bx,RMS_INT * 4
mov word ptr [bx],offset hboot
mov bx,RMS_INT * 4 + 2
mov word ptr [bx],cs
mov ds,cs:dataloc
mov ip_base,0
mov brkflg,0
mov brkds,ds
mov brkss,ss
mov brksp,sp
mov bx,offset id1str
call pstr
;
;Wait until the disk is ready, then boot it.
;If Control-C is typed, jump into bugger.
;
mov ax,cs ;disk tables in
mov ds,ax ;code seg
b11: mov bx,offset bootsong
call play ;chance to hit
call inastat ;a key to quit
jz b13
b12: call ina ;flush all keys
call inastat
jnz b12
mov bx,offset fault
call play ;make noise
jmp warm ;exit
b13: mov bx,offset rmsc ;check for
int RMS_INT ;drive ready
jc b11
mov bx,offset rms ;attempt to
int RMS_INT ;read the boot
jnc b20
mov bx,offset dskstr;if error,
call pstr ;nasty message
mov bx,offset fault
call play
jmp b11
b20: mov ax,bootseg ;read OK,
mov ds,ax ;make sure it's
mov bx,0 ;really a boot
mov al,[bx] ;sector,
cmp al,0fah ;(CLI)
je b21 ;if not,
mov bx,offset butstr
call pstr
mov bx,offset fault
call play
jmp b11
b21: mov bx,offset dostune
call play
mov cx,0 ;drive A:,
jmp boot ;boot system.
page
;
;This is the main command loop, where commands
;are input, etc. Any user type errors get here
;also. Some commands that cannot maintain stack
;discipline, such as return from break point,
;jump here. Look up single letter commands
;input from the console, in the command table.
;If we find one, go execute it, else barf.
;
warm: mov ss,cs:dataloc
mov sp,offset stack
mov ds,cs:dataloc ;set our DS,
mov es,dmpseg ;and ES,
wig: mov bx,offset prompt ;type prompt,
call pstr ;string in CS:
call charin ;get command
jz wig ;ignore delims
mov bx,offset ctable;table search,
mov cx,tlen ;table length,
warma: cmp al,cs:[bx] ;find it?
je warmbh ;yup.
add bx,3
loop warma
jmp error ;nope
warmbh: ;command match
mov cx,cs:[BX+1] ;get out addr
call cx ;call it,
jmp warm ;repeat.
;
;General purpose error handler. not real
;graceful.
;
error: mov bx,offset eh ;nasty msg,
call pstr
mov bx,offset blatz
call play
jmp warm
page
;
;Trace command. Set the Trace flag in the flag
;register, then execute like a 'go'.
;
trace: or brkfl,0000000100000000b
jmp gonow ;go execute,
;
;Go with or without breakpoint. If a comma is
;entered, get a breakpoint address, else just
;execute.
;
go: and brkfl,1111111011111111b
mov es,brkcs ;set 'go' seg
mov dmpseg,es ;and in ES,
mov bx,brkip ;and 'go' off
mov dmpoff,bx
call getadr ;for 'getadr'
mov brkip,bx ;set brk IP,
mov brkcs,es ;and seg,
cmp al,',' ;if a comma,
jne gonow ;breakpoint,
;
;The start addr is set, and a comma was typed.
;Get the breakpoint addr, put an INT 3 there
;and save the instruction.
;
gobrk: call getadr ;get brk addr
mov brkadr,bx ;save brk adr
mov brkseg,es
mov al,BRK_INST
xchg al,es:[bx] ;set brk inst,
mov brkinst,al ;save old inst
mov brkflg,1 ;set flag,
;
;Restore regs and return.
;
gonow: cli ;no ints,
mov ax,brkax
mov bx,brkbx ;restore a
mov cx,brkcx ;bunch of regs
mov dx,brkdx
mov di,brkdi
mov si,brksi
mov bp,brkbp
mov ss,brkss ;set SS and
mov sp,brksp ;stack pointer,
push brkfl ;push flags,
push brkcs ;far address,
push brkip
mov es,brkes ;restore ES,
mov ds,brkds ;and DS,
iret ;call address
page
;
;Breakpoint entry. Executed only via a jump
;from the restart location. Breakpoints
;require lots of the users stack. All registers
;are saved and displayed.
;
;Decrement the go counter; if not zero yet,
;display the regs and go reexecute from there.
;
brkntr: push ds
mov ds,cs:dataloc ;set DS,
pop brkds ;save DS,
pop brkip ;IP,
pop brkcs ;CS,
pop brkfl ;flags,
mov brkax,ax ;save regs,
mov brkbx,bx
mov brkcx,cx
mov brkdx,dx
mov brksi,si
mov brkdi,di
mov brkbp,bp
mov brkes,es
mov brkss,ss
mov brksp,sp
mov ss,cs:dataloc ;set stack,
mov sp,offset stack
sti ;enable ints,
mov ax,brkip ;set variables
mov dmpoff,ax ;for debug,
mov ax,brkcs
mov dmpseg,ax
test brkflg,1 ;breakpoint?
jz bknbh ;return if not.
dec brkip ;put pc back
mov bx,brkadr ;restore the
mov es,brkcs ;instruction
mov al,brkinst
mov es:[bx],al
bknbh: mov brkflg,0 ;no more brkpt
call regdmp ;dump the regs
jmp warm ;and stop.
page
;
;Register control command. X<CR,comma,space>
;displays all registers. X<reg name> displays
;the current register value, and allows
;entering al new value. The legal register
;names are in al table in the byte section.
;
registers:
call charin
je regdmp ;Z set if delim
jmp regchg ;if not a delim
regdmp: mov bx,offset regstr1 ;type top lin
call pstr ;of the display
mov bx,brkax
call outhex ;type ax,
mov bx,brkbx
call outhex ;type bx,space
mov bx,brkcx
call outhex ;type cx,space
mov bx,brkdx
call outhex ;type bx,spaces
mov bx,brksi
call outhex ;si, spaces,
mov bx,brkdi
call outhex ;di, spaces,
mov bx,brksp
call outhex ;type sp
mov bx,brkip ;type IP,
sub bx,ip_base ;minus offset,
call outhex
mov bx,ip_base
call outhex ;reloc reg,
mov bx,offset regstr2 ;next line,
call pstr
mov bx,brkcs ;type seg regs
call outhex
mov bx,brkds
call outhex
mov bx,brkes
call outhex
mov bx,brkss
call outhex
mov bx,brkbp ;and the BP reg
call outhex
mov es,brkss ;get two top
mov si,brksp ;stack values,
cld
mov bx,es:[si]
call outhex ;type TOS,
mov bx,es:[si+2]
call outhex ;then NOS,
mov ax,brkfl
call axtobin ;type flags,
ret
page
;
;Modify pseudo registers. The registers are
;hardcoded in the same order as they appear in
;RAM. AL contains the first letter of the
;register, get the second letter in AH, then
;look it up.
;
regchg: mov ah,al
call charin
cmp ax,'ip' ;special case
je regip ;IP,
mov si,offset regtbl ;reg names,
mov bx,offset dmp_ptr; reg values,
mov cx,rtblen ;table length,
rchal: cmp ax,cs:[si] ;match?
je pair ;go change.
add si,2 ;next...
add bx,2
loop rchal
jmp ERROR ;none!
;
;Change a word in memory.
;
pair: mov cx,[bx] ;get value,
xchg bx,cx ;to BX,
call xreg ;change it,
xchg cx,bx ;to CX,
mov [bx],cx ;update.
ret
;
;Display a value, and get a new one.
;
xreg: call outhex ;display it,
mov al,'='
call charout
call inhex ;get a new one.
ret
;
;Register IP. Display current IP minus
;'ip_base', add it in when storing it.
;
regip: mov bx,brkip
sub bx,ip_base ;adjust,
call xreg ;change,
add bx,ip_base ;adjust again,
mov brkip,bx ;store.
ret
page
;
;display memory as 8 lines of 16 bytes,
;followed by 16 of ASCII. es: is our data
;segment pointer.
;
dump: call getadr ;get address,
mov cx,8 ;do i= 1,8
dmpal: call crlf ;newline,
call outadr ;type addr,
push cx ;save count,
mov cx,16 ;do j=1,16
push bx ;save for ASCII
dmpbh: mov al,es:[bx]
call out2h
inc bx
mov dmpoff,bx
loop dmpbh ;do 16 bytes
pop bx ;now dump ASCII
mov cx,16
dmpbl: mov al,es:[bx]
inc bx ;same bytes,
and al,7fh
cmp al,' '
jae dmpd
mov al,'_'
dmpd: call charout
loop dmpbl
pop cx ;get line count
loop dmpal ;next line,
ret
page
;
;Examine/change memory. An address is entered,
;and bytes are displayed after the address.
;New values may be entered, or the left
;unchanged by typing only al delimiter. Comma
;and space close the current location, and open
;the next location. A <CR> closes the current
;location and quits. Typing bad hex aborts the
;current location.
;
memchg:
call getadr ;get start addr
memal: call crlf
call outadr ;type address,
mov dmpoff,bx ;save addr,
mov al,es:[bx] ;get old,
call out2h ;type old,
mov al,es:[bx]
mov bl,al ;put old in bl,
call inhex ;maybe get new,
mov dh,bl ;put new in dh,
mov bx,dmpoff ;get addr again
mov es:[bx],dh ;write to mem
cmp al,CR ;was char a CR?
jz sret ;exit if so.
inc bx ;next location.
cmp al,LF ;if it was LF,
jnz memal ;dec instead of
dec bx ;incrementing.
dec bx
jmp memal
sret: ret
page
;
;fill memory with al number. get two addresses,
;then the filler. Cannot fill across segment
;boundaries.
;
fill: cld
call getadr
call inhex ;get 2nd addr
cmp al,':' ;dont allow 2nd
jne fllok ;segment,
jmp error ;count 64k max.
fllok: mov cx,dmpoff ;cx is lo addr,
sub bx,cx ;bx is hi addr,
xchg bx,cx ;cx is count,
push bx ;bx is lo addr
call ghex0 ;get fill char,
mov al,bl
pop di ;get addr,
jcxz sret ;dont do none,
rep stosb ;do it.
ret
;
;Move a block of memory. Get the <from>, <end>
;and <to> addresses, calculate the block length
;then move it. Moves correctly across segments.
;
blkmov: cld
call getadr ;get from,
mov dx,ES ;save seg,
mov si,bx
call inhex ;get end,
cmp al,':' ;dont allow a
jne blk1 ;segment here,
jmp error ;error!
blk1: mov cx,si
sub bx,cx ;cnt=end-from
mov cx,bx
call getadr ;get to,
mov di,bx ;ES is dest seg
push ds ;save our DS
mov ds,dx ;set our temp
rep movsb ;source segment
pop ds ;restore DS
ret
page
;
;Port I/O commands. These do 16 bit I/O ports,
;but only 8 bit data.
;
; Input data from a port.
;
input:
call ghex0 ;get port num
mov dx,bx
in al,dx ;read the port,
push ax
call crlf
pop ax
push ax
call out2h ;display in hex
pop ax
call altobin ;then in binary
ret
;
; Output data to a port.
;
output:
call ghex0 ;get port num
mov dx,bx
call ghex0 ;get the data,
mov ax,bx
out dx,al ;send it.
ret
;
;Do some simple hex arithmetic. Input an
;expression, display the result.
;
arith: call inhex ;get the number
call crlf ;newline,
call outhex ;display result
ret
page
;
;Load an intel hex file from the console. This
;does not support any extended hex format; just
;the old fashioned 8 bit hex. The segment is
;input from the console.
;
intel: mov dmpoff,0 ;set defaults,
mov dmpseg,40h
call getadr ;get load seg,
mov es,dmpseg
;
;Load each hex record to segment ES, with an
;offset of (dmpoff)( i.e. added to the specifie
;load address every time)
;
getrcd: call charin ;wait for colon
cmp al,':'
je iproc
cmp al,LF ;if LF, echo it
jne getrcd
call charout
jmp getrcd
iproc: mov dx,0 ;clear checksum
call in2 ;get the count,
mov cl,bl ;put in CX,
mov ch,0
call in2 ;get load addr
mov al,bl ;save hi addr,
call in2
mov bh,al ;assemble word,
mov di,bx ;put in DI,
call in2 ;record type,
cmp bl,1 ;EOF?
jz itret ;return if so,
jcxz itret ;or if no data,
;
;Read <CX> bytes to memory.
;
add di,dmpoff ;add in offset,
getb: call in2 ;get a byte,
mov es:[di],bl ;store it,
inc di ;next address,
loop getb
call in2 ;get check sum,
;
;checksum broken. Too lazy to fix it.
;
; add dl,bl ;if OK,
; jz getrcd ;repeat,
jmp getrcd ;patch fix.
iterr: jmp error ;else error.
itret: ret
page
;
;INTEL, continued.
;
;
;Input the next two digits as hex, return in
;BL. Accumulate a checksum in DX, preserve
;AX, CX.
;
in2: push ax
push cx
mov bx,0
call charin ;get a char,
call hexin ;install char,
jb iterr
call charin
call hexin
jb iterr
pop cx
pop ax
add dl,bl ;checksum
ret
page
;
;Examine/change an interrupt vector. The
;input number is checked for 0-ff, the
;address of it made, the contents displayed.
;The contents can be changed by typing in
;the new seg:off, or CR to leave unchanged.
;
intvec: call ghex0 ;get int num,
call crlf ;newline,
and bx,255 ;0-255,
shl bx,1 ;times 2,
shl bx,1 ;times 4,
mov ax,0
mov es,ax ;seg 0,
push bx ;save vec addr
push es ;in es:BX,
push ip_base ;relocation
mov ip_base,0 ;off,
call outadr ;display addr,
mov ax,es:[bx+2] ;get int seg,
mov bx,es:[bx] ;get int off,
mov es,ax ;to es:BX
mov dmpseg,es ;Set default
mov dmpoff,bx ;for 'getadr',
call outadr ;display it,
call getadr ;get new,
mov cx,es ;copy es:BX to
mov dx,bx ;CX:DX,
pop ip_base ;restore reloc,
pop es ;get back int
pop bx ;vector addr,
mov es:[bx+2],cx ;store new
mov es:[bx],dx ;vector.
ret
page
;
;Boot either a hard disk or floppy. Get either
;'f', 'h' or 'm', then a number. Attempt to
;read the boot sector to memory, then execute
;it, unless the number has bit 15 set.
;
dboot: call charin ;get disk,
mov si,offset btbl ;search table
db1: cmp al,cs:[si] ;find it?
je db2
add si,blen ;no, next..
cmp byte ptr cs:[si],0
jne db1 ;no more?
jmp error
db2: call ghex0 ;get number,
mov ax,cs ;disk tables
mov ds,ax ;in code seg
push bx ;save it,
mov bx,cs:[si + 1] ;disk table
call word ptr cs:[si + 3] ;read disk
pop cx
mov ds,cs:dataloc ;set DS
mov bx,offset dskstr
jc db4 ;if OK,
test cx,8000h ;and MSB set,
jz db3
jmp warm ;dont boot
db3: mov bx,bootseg ;look at
mov es,bx ;1st instruct,
mov bx,0 ;must be CLI,
cmp byte ptr es:[bx],0fah
mov bx,offset butstr
jne db4
call boot ;attempt it,
mov bx,offset dskstr
db4: call pstr
jmp warm
btbl db 'f'
dw dd1024
dw offset cgroup:execute
blen = $ - btbl
db 'd'
dw dd1024
dw offset cgroup:execute
db 's'
dw sd128
dw offset cgroup:execute
db 'h'
dw rms
dw offset cgroup:dtc
db 'm'
dw ibm
dw offset cgroup:execute
db 0
page
;
;get an address, or use dump address. If a
;segment is specified, set ES. Return AL =
;delimeter character.
;
;This adds ip_base to BX before return. RR
;defaults to 0000 at power up. Does not affect
;dmpoff so that setting RR to 0000 again
;correctly displays the right value.
;
getadr: mov ah,1 ;set flag,
mov bx,dmpseg ;default seg
call inhex ;if we set seg
cmp al,':'
jne setadr
mov dmpseg,bx ;update ES,
mov ES,bx
mov bx,dmpoff
call inhex ;then set the
jmp gtaret ;address,
setadr: dec ah ;not seg, if BX
jnz gtaret ;changed return
mov bx,dmpoff ;new else get
gtaret: mov dmpoff,bx ;old number,
test noreloc,1 ;if flag set,
jnz gtret ;dont offset.
add bx,ip_base ;add in offset,
gtret: ret
;
; type bx as hex, followed by a space.
;
outhex: call typehex
jmp o2spc
typehex:mov al,bh ; most first
call out2
mov al,bl ; do least
call out2
ret
;
;display an address; SSSS:AAAA
;
outadr: push bx
mov bx,es ;print
call typehex ;segment:offset
mov al,':'
call charout
pop bx ;save BX,
push bx
sub bx,ip_base ;adjust for
call outhex ;display,
pop bx ;restore,
ret
page
;
;type al as hex.
;
out2: push ax
push cx
mov cl,4
shr al,cl
pop cx
call out1h
pop ax
;
;type lsnybble of al.
;
out1h: and al,0fh ;only ls 4 bits
or al,'0' ; make ascii
cmp al,'9'+1
jb out1
add al,'a'-'9'-1 ; 0-9,al-f
out1: jmp charout
;
; output al as hex followed by a space.
;
out2h: call out2 ;type al in hex
;
;type a space
;
o2spc: mov al,' '
jmp out1
page
;
;Input a hex into BX, default the number to
;zero.
;
ghex0:
mov bx,0 ;fall through
;
;Input a hex number to BX. If only a delimiter
;is typed, return with no change in BX or AH.
;If any number is input, AH is cleared.
;Supports the following special characters:
;
; .<reg> value of register <reg>
; +<xxxx> sum of current value and
; additional value <xxxx> + may
; be entered after any number of
; digits are typed, including dot
; - same as above, except
; difference of 1st and 2nd value
; (first-second)
; * Return theproduct of the current
; number and the next entered
; number.
; ! Suppresses relocation of offset
; by GETADR. Cleared on each call.
;
;Be careful when changing, as it uses
;recursion. Note that 'scratch' stores the LAST
;delimiter and is not saved each iteration.
;Jumps to error if anything goes wrong.
;
inhex: mov noreloc,0 ;clear flag,
call charin ;get char
jne inha ;exit on CR,
jmp inhret
inha: mov bx,0 ;else seed it
inhb: mov ah,0 ;mark changed.
cmp al,'+' ;check special
jne inm ;chars, if plus
push bx ;save current,
call inhex ;get another,
mov scratch,al ;save delim,
pop ax
add bx,ax ;add in new one
;splice after "ah,0 "
mov ah,0 ;change flag,
mov al,scratch ;get delim
ret ;return now.
inm: cmp al,'-' ;if minus,
jne instar
push bx ;save first val
call inhex ;get second,
mov scratch,al ;save delim
mov ax,bx
pop bx
sub bx,ax ;first-second,
mov ah,0
mov al,scratch
ret
instar: cmp al,'*' ;if star,
jne indot
push cx ;save regs,
push dx
push bx ;save current,
call inhex ;get next,
mov scratch,al ;save delim,
pop ax ;get last,
mov cx,bx ;mult to CX,
mul cx ;product,
mov bx,ax ;to BX,
pop dx
pop cx ;restore,
mov al,scratch
mov ah,0 ;BX changed.
ret
indot: cmp al,'.' ;if dot, use
jne insup ;a register,
call regval ;get reg value,
jnc indot1 ;if not found,
jmp error
indot1: mov ah,0
jmp nxtchr
insup: cmp al,'!' ;if suprise,
jne notspec
mov noreloc,1 ;suppress off
jmp nxtchr
notspec:call hexin ;digit to hl,
jae nxtchr ;hex error?
jmp error ;garbage.
nxtchr: call charin ;another char
jnz inhb ;continue,
ret ;until a delim.
page
;
;check the char in (al) for hex, return carry
;if not. install digit into bx.
;
hexin: sub al,'0' ;make hex,
jz hin ;ok if 0,
jb inhret ;if .lt. 0,
hxc: cmp al,10 ;do if .le. 9,
jb hin
sub al,27h ;if a-f, hex.
cmp al,16 ;carry if below
cmc ;now carry if
jb inhret ;above,
hin:
add bx,bx ;times 16,
add bx,bx
add bx,bx
add bx,bx
or bl,al ;add in digit,
clc ;no error.
inhret: ret
;
;Get the ASCII name of a register, and return
;it's current value in BX. Return carry set if
;not a legal register.
;
regval: push si
push cx
call charin ;get 1st char,
mov ah,al ;MS byte,
call charin ;AX is name,
cmp ax,'ip' ;special case
je retip ;IP,
mov si,offset regtbl;reg names,
mov bx,offset dmp_ptr; reg values,
mov cx,rtblen
rv1: cmp ax,cs:[si] ;match?
je rv2 ;go change.
add si,2 ;next...
add bx,2
loop rv1
stc ;not found,
jmp rv3 ;return error.
rv2: mov bx,[bx] ;get value,
clc ;return good,
rv3: pop cx ;restore,
pop si
ret
;
;Return the value of IP adjusted by 'ip_base'.
;
retip: mov bx,brkip
sub bx,ip_base
clc
jmp rv3
page
;
;Type ax in binary.
;
axtobin:mov cx,16
jmp nnbit
;
;Type al in binary. Type 1's as 1, 0's as 0.
;
altobin:mov cx,8
mov ah,al
nnbit: mov dl,'0'
shl ax,1
adc dl,0
push ax
mov al,dl
call charout
pop ax
loop nnbit
jmp o2spc
;
; print a string.
;
pstr: mov al,cs:[bx]
test al,al
je psret
call charout ;type until a 0
inc bx
jmp pstr
;
;do a crlf
;
crlf: mov al,cr
call charout
psret: ret
page
;
;Wait for a character, and return in AL. Leave
;the Z bit set if the char is one of our
;delimiters. Convert to lower case.
;
charin:
call INA ;get one char
and al,7Fh
cmp al,'9'+1 ;to lower
jb chial ;case,
or al,20h ;set shift bit,
chial: cmp al,LF ;dont echo LF's
jz inaret ;return Z set,
push ax ;indicate delim
call OUTA ;echo it,
pop ax
;
;Here we check for the legal hexadecimal number
;delimiters.
;
cmp al,CR ;check delim,
jz inaret
cmp al,','
jz inaret
cmp al,' '
jz inaret
cmp al,LF
jz inaret
cmp al,':'
inaret: ret
;
;Output a character to the console.
;
charout:
cmp al,CR ;if CR, do a LF
jnz out
call out
mov al,LF
out: call OUTA
ret
page
;
;init each device to the minimum necessary
;to run the debugger. The BIOS will fully
;init everything once booted.
;
ioinit: mov al,8ah ;8255 0, A out
out ppictl,al ;B in C0-3 out
mov al,0 ;C4-7 in
out ppia,al ;outputs off
mov al,1 ;select drive 0
out selp,al ;for the 1793,
mov al,fintc
out comp,al ;force interrup
mov al,0Eh
call set8251 ;dummy mode
mov al,40h
call set8251 ;reset 8251
mov al,4Eh
call set8251 ;8 bt async *16
mov al,37h
call set8251 ;enable Tx & Rx
mov al,0B6h
out pitmode,al ;ch.2 sq wave
mov ax,baud
out pittmr2,al ;low baud rate
mov al,ah
out pittmr2,al ;high baud rate
;
;Setup 8259 Programmable Interrupt Controller
;
mov al,13h
out pici1,al ;8086 mode
mov al,00h
out pici2,al ;vector
mov al,1Fh
out pici2,al ;EOI master
mov al,0FFh
out pici2,al ;all levels off
page
;
;Initialize the RMS and DTC86. Do a
;considerable delay here, since I think theres
;a problem with the Xebex powering up slowly.
;
mov cx,-1
xdel: aam
loop xdel
call dskinit ;init RMS disk,
ret
;
;Set a control byte to the 8251, delaying
;after each one.
;
set8251:
out pcimode,al
mov cx,100
s8: jmp $ + 2
loop s8
ret
page
;
;Character drivers.
;
;
outa: push ax
opoll: in al,pcimode
and al,1
jz opoll
pop ax
out pcidata,al
ret
;
;Input a character from the console. Turn
;interrupts off, so we can get chars while
;MSDOS is running.
;
ina: pushf
cli
inw: call inastat
jz inw
in al,pcidata
popf
inret: ret
inastat:
in al,pcimode
and al,2
ret
page
;
;Play a tune; BX points to a sound table.
;
play: mov dx,cs:[bx] ;get a note,
mov cx,cs:[bx + 2] ;get duration
add bx,4
cmp dx,ENDNOTE ;quit if end
je plz
call note
jmp play
plz: ret
;
;Play a note; BX is the divisor, CX is the
;duration. If the note is 0, pause.
;
note: mov al,0
out ppic,al ;sound off,
cmp dx,NONOTE ;if a sound,
je sd1
mov al,36h ;timer 0 mode 3
out pitmode,al
mov al,dl ;select sound
out pittmr0,al
mov al,dh
out pittmr0,al
mov al,1
out ppic,al ;enable sound,
sd1: mov ax,1000
sd2: dec ax ;delay
jnz sd2
loop sd1
mov al,0 ;disable sound
out ppic,al
ret
page
;
;Initialize the RMS disk and Xebec controller.
;Assumes an RMS 512; this is adequate for
;booting the system. The BIOS will init it
;for the correct number of tracks, etc.
;
cyls equ 153 ;cylinders
heads equ 8 ;heads,
comptrk equ 77 ;precomp trk,
ecclen equ 11 ;ECC length,
;
;initialization tables. These get copied to
;RAM, so it can be DMA'd to the DTC.
;
romtbl label byte
db 12,0,0,0 ;init drv
db 0,0,0,0,0 ;characteristic
;
;Initialization data.
;
db high cyls
db low cyls
db heads
db high comptrk
db low comptrk
db high comptrk
db low comptrk
db ecclen
tblen equ $ - romtbl
dskinit:
mov bx,offset cmdtbl ;copy the
mov si,offset romtbl ;table to RAM
mov cx,tblen ;so we can DMA
di1: mov al,cs:[si]
mov [bx],al
inc si
inc bx
loop di1
in al,ccr ;clr old DONE,
mov ax,ds
mov cx,16
mul cx
add ax,offset cmdtbl
adc dx,0
out cal,al
mov al,ah
out cah,al
mov al,dl
out cat,al
mov ax,ds
mul cx
add ax,offset dattbl
adc dx,0
out dal,al
mov al,ah
out dah,al
mov al,dl
out dat,al
mov al,0
out csr,al ;start it,
ret
page
;
;Western Digital 1793 Floppy Controller.
;Accepts a standard Fido disk table at
;DS:BX, performs the function, returns
;status in carry and AL.
;
;
;Make our commands and error masks.
;
cread equ readc or waitb or mulb
cwrite equ writec or waitb or mulb
cseek equ seekc or updb ; or stepb
chome equ homec or updb ; or stepb
creadh equ readh
readm equ sekrb or crcb or ntrdyb
writem equ sekrb or crcb or wrtrb or wprotb or ntrdyb
seekm equ ntrdyb or sekrb or crcb
readhm equ readm
dmawb equ 64 ;DMA write
dmarb equ 128 ;DMA read
dmacb equ 64h ;DMA mode bits
page
;
;Returns carry clear if the operation was OK,
;else the MSDOS error code in AL. No table
;parameters are modified. The caller must
;perform diagnostics and retries.
;
;This driver will read one or more sectors
;on a given track. The caller must make
;seperate calls for each track read.
;
execute:
mov al,0
out modstp,al ;stop DMA,
call seldrv ;select drive,
jc drw15 ;error!
in al,statp ;if busy,
test al,busyb
jz drw0
call abort ;abort whatever
jc drw15
drw0: call seek ;seek to track,
jnc drw1
drw15: jmp fret
drw1: mov ax,sector[bx] ;set sector,
;
;Patch location: install a DEC AL here for the
;Tecmar non-standard diskettes.
;
wdpatch:sub al,0
out secp,al
;
;Make byte count from sector size and sector
;count. Adjust for the 8257.
;
mov ax,count[bx] ;count =secsiz*
mov cx,secsiz[bx] ;#sectors,
mul cx ;make count,
page
;
;Put the count to the 8257, adding in the right
;DMA direction bit, depending on the floppy
;command.
;
setdma: and ax,3fffh ;max count,
dec ax ;adjust
out ch2cp,al ;out LS byte,
cmp byte ptr command[bx],fwrite ;if write,
mov al,dmarb ;DMA read, else
je setdm
setr: mov al,dmawb ;DMA write,
setdm: or al,ah ;add direction,
out ch2cp,al ;output it,
mov ax,dmaseg[bx] ;make a 20 bit
mov cx,16 ;address,
mul cx ;4 bits in DX,
add ax,dmaoff[bx] ;add in offset
adc dx,0 ;prop. carry,
out ch2ap,al ;set,
mov al,ah
call delay ;delay for 8257
out ch2ap,al
mov al,dl
and al,0fh ;strip it,
;
;Ones Complement for Comark MF-85 ONLY.
;
not al ;complement,
out pagep,al ;select page,
page
;
;Execute the command. If 'fcheck', make sure
;the header matches the disk type. If all's
;well, return carry clear, else carry set and
;AL == error code.
;
dorw: call exrw ;execute it,
jc drz ;error!
cmp byte ptr command[bx],fcheck
clc ;if fmt check,
jne drz
push es
les si,dword ptr dmaoff[bx]
mov al,es:[si+3] ;get sec size,
pop es
cmp al,enn[bx] ;same?
je drz
mov al,7 ;"media error"
stc
drz: ret
;
;Issue the floppy command, wait for DMA done
;then check floppy status and abort it. While
;we look for DMA done, watch BUSY so we dont
;hang. Return carry set and AL == 4 if error.
;
exrw: mov al,dmacb
out modstp,al ;start DMA,
mov al,cread
mov dh,readm
cmp byte ptr command[bx],fread
je sw1
mov al,cwrite ;get cmd,
mov dh,writem ;error mask,
cmp byte ptr command[bx],fwrite
je sw1
mov al,creadh
mov dh,readhm
sw1: out comp,al ;issue it,
swt: call delay ;delay,
in al,modstp ;get status,
and al,4 ;if DMA EOP,
jnz retstat ;return status,
in al,statp ;check ready
and al,ntrdyb or busyb ;and busy,
cmp al,busyb
je swt
retstat:call delay
in al,statp ;get status
push ax ;save it,
call abort ;stop it,
pop ax ;get em back,
and al,dh ;mask err bits
jz fret ;ret if zero,
test al,wprotb ;write prot?
mov al,0
jnz ferr ;else
mov al,4 ;DATA ERROR,
ferr: stc
fret: ret
page
;
;Internal seek command. Returns Z set if OK.
;Returns carry set and AL error code if error.
;
seek: mov ax,curtrk[bx] ;if at an
cmp ax,-1 ;unknown trk,
je sk1
cmp ax,0 ;or seek trk 0,
jne sk2
sk1: mov al,chome or l6ms
sk1a: call cmdout ;recal drive,
jc skz ;error! else
mov ax,0 ;current track,
sk2: out trkp,al ;set cur'nt trk
mov ax,track[bx] ;seek to trk,
out datp,al
mov al,cseek or l6ms or verb
test byte ptr density[bx],2
jz sk2a
mov al,cseek or m6ms or verb
sk2a: call cmdout
jc skz
and al,seekm ;check error,
jz skz
mov al,6 ;"seek error"
stc
skz: ret
page
;
;Execute the floppy command in AL, return
;carry set and AL =2 if not ready, otherwise
;return status in AL.
;
cmdout: out comp,al ;issue command,
cmd1: call delay ;wait for 1791,
in al,statp ;get status,
test al,ntrdyb ;chk not rdy,
jnz cmderr
; test al,busyb ;busy?
; jz cmd1
cmd2: call delay
in al,statp ;wait for
test al,ntrdyb ;not busy,
jnz cmderr ;(look for
test al,busyb ;not rdy)
jnz cmd2
ret
cmderr: mov al,2 ;"not ready"
stc
ret
page
;
;Select the disk by changing disk number to a
;select bit, and set the density. Make sure
;the drive is ready after the select.
;
seldrv: mov cl,drive[bx] ;get the drive
mov al,1 ;set drive 0,
shl al,cl ;make select
test byte ptr density[bx],1
jnz sl1 ;if single dens
or al,singlb ;select it,
sl1: or al,patchb ;fix hardware
cmp word ptr head[bx],0
je sl15
or al,80h ;2nd head,
sl15: test byte ptr density[bx],2
jz sl3
;
;Minifloppy. Turn on the motor, and if
;the curent track is -1, delay for motor
;on. The problem is that we dont know if
;the motor was on or not, and we dont want
;to delay every time, so this is a quick fix.
;
or al,minib ;mtr on, ready
out selp,al ;start it,
cmp word ptr curtrk[bx],-1
jne sl3
mov cx,500 ;500 mS delay
sl2: call delay ;for motor on
loop sl2
sl3: out selp,al ;select drive,
mov cx,100 ;1mS
sl4: call delay ;delay,
loop sl4
;
;Check drive ready. Wait a bit for it to
;become ready. Return carry and AL == 2 if
;it doesn't.
;
sl5: mov cx,5000 ;retries,
sl6: call delay
in al,comp
and al,ntrdyb ;if ready,
jz slz ;return,
loop sl6
mov al,2
stc
slz: ret
;
;Abort the current operation by issuing a force
;interrupt command, and waiting for busy to go
;away.
;
abort: xor al,al ;stop DMA,
out modstp,al
mov al,fintc
ab1: mov cx,1000
out comp,al
abrt: call delay
in al,statp
test al,busyb ;wait no busy,
loopnz abrt
jz ab2
mov al,12 ;"disk err"
stc
ab2: ret
;
;Software delay for use with fast 10MHz 8086's.
;
; call delay ;19
delay: push cx ;11
mov cx,15 ;(4 to 8) *15,
dly: jmp $ + 2 ;clear the queue
loop dly ;17/5
pop cx ;8
ret ;8
page
;
;DTC-86 / Xebec Controller driver. This assumes
;an RMS drive attached as drive 0.
;Accepts a standard Fido disk table at
;DS:BX, performs the function, returns
;status in carry and AL.
;
;
;Perform the IO, return carry set and an MSDOS
;error code in AL if failure.
;
dtc: push ds ;point ES to
pop es ;cmd block,
push ds
mov ds,cs:dataloc ;set DS,
mov ax,ds ;set cmd addr
mov cx,16
mul cx ;20 bit addr
add ax,offset xcomand
adc dx,0
out cal,al ;out 3 bytes,
call delay
mov al,ah
out cah,al
call delay
mov al,dl
out cat,al
call delay
mov ax,es:dmaseg[bx]
mul cx ;same for data
add ax,es:dmaoff[bx]
adc dx,0
out dal,al ;out 3 bytes,
call delay
mov al,ah
out dah,al
call delay
mov al,dl
out dat,al
call delay
page
;
;Calculate the logical sector, put it in the
;table.
;
mov ax,es:track[bx] ;AX= track,
mov dx,0
mul word ptr es:spt[bx] ; *SPT,
mov cx,es:sector[bx]
dec cx ;make 0-N,
add ax,cx
adc dx,0
mov lowaddr,al ;store low,
mov hiaddr,ah ;high sec,
and dl,0fh ;top sec,
mov al,es:drive[bx] ;make LUN,
mov cl,5
shl al,cl
or al,dl ;add in,
mov lun,al ;store it,
mov control,4 ;type =RMS,
mov ax,es:count[bx]
mov scount,al ;set sec count,
mov al,es:command[bx]
; mov xcomand,xwrite
; cmp al,fwrite
; je dtc1
mov xcomand,xread
cmp al,fread
je dtc1
mov xcomand,xcheck
cmp al,fcheck
je dtc1
stc ;illegal cmd
jmp dtc3
dtc1: in al,ccr ;clear old done
mov al,0
out csr,al ;start it,
dtc2: call delay
in al,csr ;wait for DONE,
test al,80h
jz dtc2
call delay
in al,ccr ;sample ERROR,
and al,2 ;clears DONE,
jz dtc3
stc ;error!
dtc3: pop ds
ret
code ends
end bugger